package test;

import com.graphhopper.util.GPXEntry;
import edu.buaa.act.helper.Utils;

import java.io.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

/**
 * Created by T7810 on 2017/3/10.
 *
 * input raw txt format file, output GPX format file
 * which will be used as input of map-matching.
 *
 */
public class TxtToGPS
{

    File inputFile;
    File outputFile;

    public TxtToGPS(File filePath, File targetGPSDir){
        inputFile = filePath;
        outputFile = targetGPSDir;
    }

    public TxtToGPS(File inputFile)
    {
        this.inputFile = inputFile;
    }



    /**
     * convert function for newzhuanche.txt, which is generated (which means after linear
     * interpolation and K-d anonymous) from zhuanche.txt
     *
     * this function is the same as convertPhase1data, but with two difference:
     * 1. file rotation support.
     * 2. reduction of data amount, remove data inserted by linear interpolation.
     * reason: because graph-hopper's map-matching lib cannot accept a very long trajectory. so
     * we have to cut them into pieces. The trajectory is cut when the car report no data
     * in last 1 hour.
     *
     * input file format:
     * carID time_slot latitude longitude
     * 1 0 39.959760 116.552365
     *
     * carID is re-arranged into 1 to 94 (but has the same meaning as before. e.g. distinct)
     *
     * time_slot: 5 seconds offset. range from 0 to 436308.
     * current timestamp(in seconds) = time_slot * 5 + 333570 + timestampInSeconds(2016-03-01 00:00:00 GMT+8)
     * i.e. the timeline is from 2016-03-04 20:39:30(GMT+8) to 2016-03-30 02:38:30(GMT+8)
     * the timeline is cut off because we choose the common timeline when every car has position.
     *
     * if there is no gps point at a specific time, we use linear interpolation to fill it. (thus we assume
     * the car's speed is unchanged between the two points that come from raw data).
     *
     * so every car at every 5 seconds has a position.
     *
     * @throws IOException
     * @throws ParseException
     */
    public void convertAnonymousData() throws IOException, ParseException
    {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+08:00");
        df.setTimeZone(TimeZone.getTimeZone("GMT+8:00")); // "UTC"
        long initialTimestamp = df.parse("2016-03-01T00:00:00+08:00").getTime() + 333570*1000;


        List<GPXEntry> list = new ArrayList<GPXEntry>();

        BufferedReader ir = new BufferedReader(new FileReader(inputFile));
        String lineTxt = null;
        boolean firstLoop=true;
        long lastCarID=0;
        while((lineTxt = ir.readLine()) != null)
        {
            String[] arr = lineTxt.split("\t");
            long carID = Long.parseLong(arr[0]);
            int timeSlot = Integer.parseInt(arr[1]);
            float latitude = Float.parseFloat(arr[2]);
            float longitude = Float.parseFloat(arr[3]);

            if(carID!=lastCarID) break;
            lastCarID = carID;

            long timeStamp = initialTimestamp + ((long)timeSlot) * 5 * 1000;

            list.add(new GPXEntry(latitude, longitude, timeStamp));
        }
        ir.close();
    }

    public static void main(String[] args)
    {
        try
        {
//            File rawTrajectoryFile= Utils.getExistFile("data/out.txt");
//            File outputGPXFile = Utils.getFile("data/out1.gpx");
//            "data/newzhuanche.txt"
            File rawTrajectoryFile= Utils.getExistFile("data/zhuanche.txt");
            File outputGPXFile = Utils.getFile("data/zhuanche201603.gpx");
            new TxtToGPS(rawTrajectoryFile, outputGPXFile).convert();
//            new TxtToGPS(rawTrajectoryFile, outputGPXFile).convertPhase1data();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

    }

    /**
     * convert function for zhuanche.txt, which is the raw data got from CAR-NETWORKING group.
     *
     * input file format:
     * carID time latitude longitude
     * 967790112788 26766 39.959760 116.552365
     *
     * carID is unique
     * time is the seconds offset from 2016-03-01 00:00:00 GMT+8
     * timeline is from 2016-03-01 00:00:00 GMT+8 to 2016-03-31 23:59:59 GMT+8
     * latitude and longitude is WGS84 raw data
     *
     * output file:
     * if the car is not report GPS position in 200 seconds, we treat it as a new trajectory segment.
     *
     * @throws IOException
     * @throws ParseException
     */
    @Deprecated
    public void convert() throws IOException, ParseException
    {
        // if not receive new point in 200s then regard next point as begin of a new trajectory.
        final int trajectoryTimeGap = 200;

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+08:00");
        df.setTimeZone(TimeZone.getTimeZone("GMT+8:00")); //UTC
        long initialTimestamp = df.parse("2016-03-01T00:00:00+08:00").getTime();


        BufferedWriter ow = new BufferedWriter(new FileWriter(outputFile));
        ow.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?><gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" creator=\"Graphhopper\" version=\"1.1\" xmlns:gh=\"https://graphhopper.com/public/schema/gpx/1.1\">\n");
        ow.write("<trk>\n");


        BufferedReader ir = new BufferedReader(new FileReader(inputFile));
        String lineTxt = null;
        boolean firstLoop=true;
        long lastCarID=0;
        int lastTimeOffsetSecond=0;
        int count =0;
        while((lineTxt = ir.readLine()) != null)
        {
            String[] arr = lineTxt.split(" ");
            long carID = Long.parseLong(arr[0]);
            int timeOffsetSecond = Integer.parseInt(arr[1]);
            float latitude = Float.parseFloat(arr[2]);
            float longitude = Float.parseFloat(arr[3]);

            if(firstLoop)
            {
                lastCarID = carID;
                firstLoop = false;
                ow.write("<trkseg>\n");
                lastTimeOffsetSecond = timeOffsetSecond;
            }
            else
            {
                if(carID!=lastCarID) break;
                if(count>40000) break;
                count++;

                if( timeOffsetSecond - lastTimeOffsetSecond > trajectoryTimeGap) // create new trajectory segment.
                {
                    ow.write("</trkseg>\n");
                    ow.write("<trkseg>\n");
                }

                String timeStr = df.format(initialTimestamp + ((long)timeOffsetSecond) * 1000);

                ow.write("<trkpt lat=\"");
                ow.write(String.valueOf(latitude));
                ow.write("\" lon=\"");
                ow.write(String.valueOf(longitude));
                ow.write("\"><time>");
                ow.write(timeStr);
                ow.write("</time></trkpt>\n");

                lastTimeOffsetSecond = timeOffsetSecond;
            }
        }
        ir.close();

        ow.write("</trkseg>\n");
        ow.write("</trk>\n");
        ow.write("</gpx>\n");
        ow.close();
    }

    /**
     * convert function for newzhuanche.txt, which is generated (which means after linear
     * interpolation and K-d anonymous) from zhuanche.txt
     * input file format:
     * carID time_slot latitude longitude
     * 1 0 39.959760 116.552365
     *
     * carID is re-arranged into 1 to 94 (but has the same meaning as before. e.g. distinct)
     *
     * time_slot: 5 seconds offset. range from 0 to 436308.
     * current timestamp(in seconds) = time_slot * 5 + 333570 + timestampInSeconds(2016-03-01 00:00:00 GMT+8)
     * i.e. the timeline is from 2016-03-04 20:39:30(GMT+8) to 2016-03-30 02:38:30(GMT+8)
     * the timeline is cut off because we choose the common timeline when every car has position.
     *
     * if there is no gps point at a specific time, we use linear interpolation to fill it. (thus we assume
     * the car's speed is unchanged between the two points that come from raw data).
     *
     * so every car at every 5 seconds has a position.
     *
     * @throws IOException
     * @throws ParseException
     */
    @Deprecated
    public void convertPhase1data() throws IOException, ParseException
    {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+00:00");
        df.setTimeZone(TimeZone.getTimeZone("UTC")); // "GMT+8:00"
        long initialTimestamp = df.parse("2016-03-01T00:00:00+00:00").getTime() + 333570*1000;


        BufferedWriter ow = new BufferedWriter(new FileWriter(outputFile));
        ow.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?><gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" creator=\"Graphhopper\" version=\"1.1\" xmlns:gh=\"https://graphhopper.com/public/schema/gpx/1.1\">\n");
        ow.write("<trk>\n");


        BufferedReader ir = new BufferedReader(new FileReader(inputFile));
        String lineTxt = null;
        boolean firstLoop=true;
        long lastCarID=0;
        while((lineTxt = ir.readLine()) != null)
        {
            String[] arr = lineTxt.split("\t");
            long carID = Long.parseLong(arr[0]);
            int timeSlot = Integer.parseInt(arr[1]);
            float latitude = Float.parseFloat(arr[2]);
            float longitude = Float.parseFloat(arr[3]);

            if(firstLoop)
            {
                lastCarID = carID;
                firstLoop = false;
                ow.write("<trkseg>\n");
            }
            else
            {
                if(carID!=lastCarID) break;

                String timeStr = df.format(initialTimestamp + ((long)timeSlot) * 5 * 1000);

                ow.write("<trkpt lat=\"");
                ow.write(String.valueOf(latitude));
                ow.write("\" lon=\"");
                ow.write(String.valueOf(longitude));
                ow.write("\"><time>");
                ow.write(timeStr);
                ow.write("</time></trkpt>\n");
            }
        }
        ir.close();

        ow.write("</trkseg>\n");
        ow.write("</trk>\n");
        ow.write("</gpx>\n");
        ow.close();
    }


    static class GPXFileRotateWriter
    {
        private BufferedWriter curWriter = null;
        private File outputFile;
        private int curNum=0;

        public GPXFileRotateWriter(File outputFile) throws IOException
        {
            this.outputFile = outputFile;
            rotate();
        }

        public void write(String str) throws IOException
        {
            this.curWriter.write(str);
        }

        public void rotate() throws IOException
        {
            this.close();
            curWriter = new BufferedWriter(new FileWriter(getFileWithNum()));
            this.writeGPXFileHeader();
            curNum++;
        }

        public void close() throws IOException
        {
            if(curWriter!=null)
            {
                curWriter.close();
            }
        }

        private File getFileWithNum()
        {
            return new File(outputFile.getAbsolutePath()+"."+curNum+".gpx");
        }

        private void writeGPXFileHeader() throws IOException
        {
            curWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?><gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" creator=\"Graphhopper\" version=\"1.1\" xmlns:gh=\"https://graphhopper.com/public/schema/gpx/1.1\">\n");
            curWriter.write("<trk>\n");
        }
    }
}
